package com.basker.pisces.plugin;

import org.springframework.core.ResolvableType;
import org.springframework.util.StringUtils;

import com.basker.pisces.spring.SpringApplicationContext;
import com.basker.pisces.utils.ReflectionUtils;

public class JavaPlugin<T> extends AbstractPlugin {

    private String className;
    private String beanName;

    private transient volatile Class<T> pluginType;

    /**
     * 创建java插件，优先使用{@link #getBeanName()}
     */
    @SuppressWarnings("unchecked")
    @Override
    public T createPluginInstance() {
        Object pluginInstance = null;

        if (!StringUtils.isEmpty(this.getBeanName())) {
            pluginInstance = SpringApplicationContext.getInstance().getBean(this.getBeanName(), Object.class, false);
        } else if (!StringUtils.isEmpty(this.getClassName())) {
            pluginInstance = ReflectionUtils.createNewInstance(this.getClassName());
        }

        this.check(pluginInstance);

        return (T) pluginInstance;
    }

    /**
     * 插件的bean名称，从springIOC获取
     *
     * @return
     */
    public String getBeanName() {
        return beanName;
    }

    /**
     * 插件的完整类名
     *
     * @return
     */
    public String getClassName() {
        return className;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    private void check(Object pluginInstance) {
        if (pluginInstance == null) {
            throw new IllegalArgumentException(this.toString() + " has no pluginInstance.");
        }

        if (this.pluginType == null) {
            this.loadPluginType();
        }

        if (!this.pluginType.isAssignableFrom(pluginInstance.getClass())) {
            throw new IllegalArgumentException(
                    this.toString() + "'s pluginInstance is not '" + this.pluginType.getName() + "'.");
        }
    }

    @SuppressWarnings("unchecked")
    private synchronized void loadPluginType() {
        Class<?>[] beanTypes = ResolvableType.forType(this.getClass()).as(JavaPlugin.class).resolveGenerics();
        this.pluginType = (Class<T>) beanTypes[0];
    }

}
